fix(typescript): map included .ts files in step output - #5685
fix(typescript): map included .ts files in step output#5685luantaraschi wants to merge 2 commits into
Conversation
Two adjacent blocks in container.js merge a transpile mapping after compiling TypeScript. The helper block merges into store.tsFileMapping; the include/support block merges only into container.tsFileMapping. Step.line() reads store.tsFileMapping, so a step whose stack frame points into an included page object had no entry to match and was printed with the deleted .temp.mjs sibling instead of the .ts source. Error stacks were unaffected because fixErrorStack() is handed the mapping directly. The include block now merges into store as well, mirroring the helper block two hundred lines above it. Closes codeceptjs#5675
|
Thanks for digging into this! Your read of the write/read mismatch is correct. Here’s a minimal browser-free config that reproduces it, with only this PR applied the Scenario Steps path is still wrong. Working ReproBrowser-free, no network, ~1.1s. CodeceptJS 4.1.0 (latest on npm) with the one-line change from this PR hand-applied to
export const config = {
tests: './tests/*Test.ts',
helpers: { FakeHelper: { require: './fakeHelper.js' } },
include: { fooPage: './pages/fooPage.ts' },
require: ['tsx/cjs'],
name: 'ts-step-paths-repro',
};
import Helper from 'codeceptjs/lib/helper';
export default class FakeHelper extends Helper {
doThing(label) { return label; }
failNow(message) { throw new Error(message); }
}
export {};
const { I } = inject();
export default {
open() {
I.doThing('called from a .ts page object under include');
},
};
Feature('ts step paths');
Scenario('reports page object step path', ({ I, fooPage }) => {
fooPage.open();
I.failNow('deliberate failure so Scenario Steps is printed');
});Result matrix
Neither change is sufficient alone, both are necessary. DefectEven with this PR’s change applied (hand-patched into The mapping entry now exists, your change works, but the lookup still misses.
Doing the mapping first, then shortening, seems to fix it: line() {
const lines = this.stack.split('\n')
if (lines[STACK_LINE]) {
- let line = lines[STACK_LINE].trim()
- .replace(store.codeceptDir || '', '.')
- .trim()
+ let line = lines[STACK_LINE].trim()
- // Map .temp.mjs back to original .ts files using container's tsFileMapping
+ // Map .temp.mjs back to original .ts files using container's tsFileMapping.
+ // The mapping holds absolute paths, so this must run before codeceptDir is
+ // shortened to '.', or the lookup can never match.
const fileMapping = store.tsFileMapping
if (line.includes('.temp.mjs') && fileMapping) {
for (const [tsFile, mjsFile] of fileMapping.entries()) {
if (line.includes(mjsFile)) {
line = line.replace(mjsFile, tsFile)
break
}
}
}
- return line
+ return line.replace(store.codeceptDir || '', '.').trim()
}
return ''
}Non-mapped step lines still shorten the same way, eg at Even when mapping works, include steps still show Line numbers are still wrong (separate issue)#5675 also mentioned wrong line numbers, and that part is not fixed by either change. Green output reports
|
|
Thanks for the detailed repro and result matrix. You're right: this PR populates the mapping, but I'll update this PR to apply the mapping before |
Motivation/Description of the PR
Resolves #5675.
@djyarber's observation that test files map correctly but included page objects do not comes down to two adjacent blocks in
lib/container.jsthat do almost the same thing and disagree about where the result goes.The helper block, around line 470, merges the transpile mapping into
store.tsFileMapping. The include/support block, around line 889, merges the same shape of mapping intocontainer.tsFileMappingonly.Step.line()inlib/step/base.js:156readsstore.tsFileMapping. So a step whose stack frame points into an included.tsmodule has no entry to match and keeps the.temp.mjspath, which by then has been deleted, hence the paths in the report.Error stacks were never affected, which is why the migration guide's promise holds for failures:
fixErrorStack()is handed the mapping object directly by the caller rather than reading it fromstore.The include block now merges into
storeas well, mirroring the helper block.Type of change
Checklist:
npm run docs) — N/A, no public API changenpm run lint)npm test)I want to be straight about the missing test. Exercising this needs a container built from a config with a TypeScript
include, transpiled for real, and I did not get a harness for that working that I would trust.test/unit/utils/typescript_test.jsdrivestranspileTypeScriptdirectly and never touches the container. A test assertingStep.line()maps a path whenstore.tsFileMappingalready holds the entry would pass before and after this change, so it would prove nothing.What I did verify is the asymmetry itself: both blocks receive the same
mappingfromtranspileTypeScript, only one writes tostore, andstoreis what the reader uses. If you point me at the right fixture or harness for a config-level include I will add the regression test.Unit suite on Windows: 758 passing / 11 failing, unchanged by this PR. Those 11 are pre-existing path assertions that expect POSIX paths and see a
C:drive letter (utils_test.js,utils/trace_test.js).